{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 案例介绍"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "案例数据来源于江苏镇江扬中市的高新区企业历史近2年的用电量，希望能够根据历史数据去精准预测未来一个月每一天的用电量，这是一个很典型的时序数据回归类问题，我们来看看如何用数据驱动的建模方法去完成这样一个预测。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 数据理解"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\workspace\\JPS_toolKit\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:3: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n",
      "of pandas will change to not sort by default.\n",
      "\n",
      "To accept the future behavior, pass 'sort=False'.\n",
      "\n",
      "To retain the current behavior and silence the warning, pass 'sort=True'.\n",
      "\n",
      "  This is separate from the ipykernel package so we can avoid doing imports until\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>record_date</th>\n",
       "      <th>user_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1135.0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>570.0</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>3418.0</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>3968.0</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>3986.0</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   power_consumption record_date  user_id\n",
       "0             1135.0  2015-01-01        1\n",
       "1              570.0  2015-01-02        1\n",
       "2             3418.0  2015-01-03        1\n",
       "3             3968.0  2015-01-04        1\n",
       "4             3986.0  2015-01-05        1"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_1 = pd.read_csv('./input/zhenjiang_power.csv')\n",
    "data_2 = pd.read_csv('./input/zhenjiang_power_9.csv')\n",
    "data = pd.concat([data_1, data_2])\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 929106 entries, 0 to 43619\n",
      "Data columns (total 3 columns):\n",
      "power_consumption    929106 non-null float64\n",
      "record_date          929106 non-null object\n",
      "user_id              929106 non-null int64\n",
      "dtypes: float64(1), int64(1), object(1)\n",
      "memory usage: 28.4+ MB\n"
     ]
    }
   ],
   "source": [
    "data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>user_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>count</td>\n",
       "      <td>9.291060e+05</td>\n",
       "      <td>929106.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>mean</td>\n",
       "      <td>2.617557e+03</td>\n",
       "      <td>727.500000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>std</td>\n",
       "      <td>3.141672e+04</td>\n",
       "      <td>419.733772</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>min</td>\n",
       "      <td>1.000000e+00</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25%</td>\n",
       "      <td>4.400000e+01</td>\n",
       "      <td>364.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50%</td>\n",
       "      <td>2.630000e+02</td>\n",
       "      <td>727.500000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>75%</td>\n",
       "      <td>8.280000e+02</td>\n",
       "      <td>1091.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>max</td>\n",
       "      <td>1.310016e+06</td>\n",
       "      <td>1454.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       power_consumption        user_id\n",
       "count       9.291060e+05  929106.000000\n",
       "mean        2.617557e+03     727.500000\n",
       "std         3.141672e+04     419.733772\n",
       "min         1.000000e+00       1.000000\n",
       "25%         4.400000e+01     364.000000\n",
       "50%         2.630000e+02     727.500000\n",
       "75%         8.280000e+02    1091.000000\n",
       "max         1.310016e+06    1454.000000"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1454"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查看企业数量\n",
    "len(data['user_id'].unique())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 929106 entries, 0 to 43619\n",
      "Data columns (total 3 columns):\n",
      "power_consumption    929106 non-null float64\n",
      "record_date          929106 non-null datetime64[ns]\n",
      "user_id              929106 non-null int64\n",
      "dtypes: datetime64[ns](1), float64(1), int64(1)\n",
      "memory usage: 28.4 MB\n"
     ]
    }
   ],
   "source": [
    "data.loc[:, 'record_date'] = pd.to_datetime(data['record_date'])\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>record_date</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             power_consumption\n",
       "record_date                   \n",
       "2015-01-01           2900575.0\n",
       "2015-01-02           3158211.0\n",
       "2015-01-03           3596487.0\n",
       "2015-01-04           3939672.0\n",
       "2015-01-05           4101790.0"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 计算地区每天的用电量\n",
    "data = data[['record_date', 'power_consumption']].groupby('record_date').agg('sum')\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption\n",
       "0  2015-01-01          2900575.0\n",
       "1  2015-01-02          3158211.0\n",
       "2  2015-01-03          3596487.0\n",
       "3  2015-01-04          3939672.0\n",
       "4  2015-01-05          4101790.0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = data.reset_index()\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x18e4371a948>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "tmp_data = data[(data['record_date'] >= '2015-09-01') & (data['record_date'] <= '2015-10-31')]\n",
    "tmp_data = tmp_data.set_index(['record_date'])\n",
    "tmp_data['power_consumption'].plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据分析：企业用电率受节假日、周末、季度以及新增企业数量等因素影响，因此需要从以下角度去进行特征构造"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 构造测试集数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2016-10-01', '2016-10-02', '2016-10-03', '2016-10-04',\n",
       "               '2016-10-05', '2016-10-06', '2016-10-07', '2016-10-08',\n",
       "               '2016-10-09', '2016-10-10', '2016-10-11', '2016-10-12',\n",
       "               '2016-10-13', '2016-10-14', '2016-10-15', '2016-10-16',\n",
       "               '2016-10-17', '2016-10-18', '2016-10-19', '2016-10-20',\n",
       "               '2016-10-21', '2016-10-22', '2016-10-23', '2016-10-24',\n",
       "               '2016-10-25', '2016-10-26', '2016-10-27', '2016-10-28',\n",
       "               '2016-10-29', '2016-10-30', '2016-10-31'],\n",
       "              dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_df = pd.date_range('2016-10-01', periods=31, freq='D')\n",
    "test_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2016-10-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2016-10-02</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2016-10-03</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2016-10-04</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2016-10-05</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date\n",
       "0  2016-10-01\n",
       "1  2016-10-02\n",
       "2  2016-10-03\n",
       "3  2016-10-04\n",
       "4  2016-10-05"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_df = pd.DataFrame(test_df)\n",
    "test_df.columns = ['record_date']\n",
    "test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2016-10-01</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2016-10-02</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2016-10-03</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2016-10-04</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2016-10-05</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption\n",
       "0  2016-10-01                  0\n",
       "1  2016-10-02                  0\n",
       "2  2016-10-03                  0\n",
       "3  2016-10-04                  0\n",
       "4  2016-10-05                  0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_df.loc[:, 'power_consumption'] = 0\n",
    "test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>26</td>\n",
       "      <td>2016-10-27</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>27</td>\n",
       "      <td>2016-10-28</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>28</td>\n",
       "      <td>2016-10-29</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>29</td>\n",
       "      <td>2016-10-30</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>30</td>\n",
       "      <td>2016-10-31</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   record_date  power_consumption\n",
       "26  2016-10-27                0.0\n",
       "27  2016-10-28                0.0\n",
       "28  2016-10-29                0.0\n",
       "29  2016-10-30                0.0\n",
       "30  2016-10-31                0.0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 拼接到一起做特征工程\n",
    "total_df = pd.concat([data, test_df])\n",
    "total_df.tail()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. 构造时间特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一些强时间特征：\n",
    "- 是否是周六日\n",
    "- 是否是法定节假日\n",
    "- 一年中的第几个月\n",
    "- 一年中的第几周\n",
    "- 一周中的星期几\n",
    "- 一月中的上、中、下旬"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>dayofweek</th>\n",
       "      <th>month</th>\n",
       "      <th>dayofmonth</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption  dayofweek  month  dayofmonth\n",
       "0  2015-01-01          2900575.0          3      1           1\n",
       "1  2015-01-02          3158211.0          4      1           2\n",
       "2  2015-01-03          3596487.0          5      1           3\n",
       "3  2015-01-04          3939672.0          6      1           4\n",
       "4  2015-01-05          4101790.0          0      1           5"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total_df.loc[:, 'dayofweek'] = total_df['record_date'].apply(lambda x:x.dayofweek)\n",
    "total_df.loc[:, 'month'] = total_df['record_date'].apply(lambda x:x.month)\n",
    "total_df.loc[:, 'dayofmonth'] = total_df['record_date'].apply(lambda x:x.day)\n",
    "total_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造周末特征\n",
    "total_df.loc[:, 'weekend_sat'] = 0\n",
    "total_df.loc[:, 'weekend_sun'] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "total_df.loc[total_df['dayofweek']==5, 'weekend_sat'] = 1\n",
    "total_df.loc[total_df['dayofweek']==6, 'weekend_sun'] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造上中下旬\n",
    "def period_of_month(day):\n",
    "    if day in range(1, 11):\n",
    "        return 1\n",
    "    if day in range(11, 21):\n",
    "        return 2\n",
    "    else:\n",
    "        return 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>dayofweek</th>\n",
       "      <th>month</th>\n",
       "      <th>dayofmonth</th>\n",
       "      <th>weekend_sat</th>\n",
       "      <th>weekend_sun</th>\n",
       "      <th>period_of_month</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption  dayofweek  month  dayofmonth  weekend_sat  \\\n",
       "0  2015-01-01          2900575.0          3      1           1            0   \n",
       "1  2015-01-02          3158211.0          4      1           2            0   \n",
       "2  2015-01-03          3596487.0          5      1           3            1   \n",
       "3  2015-01-04          3939672.0          6      1           4            0   \n",
       "4  2015-01-05          4101790.0          0      1           5            0   \n",
       "\n",
       "   weekend_sun  period_of_month  \n",
       "0            0                1  \n",
       "1            0                1  \n",
       "2            0                1  \n",
       "3            1                1  \n",
       "4            0                1  "
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total_df.loc[:, 'period_of_month'] = total_df['dayofmonth'].apply(lambda x:period_of_month(x))\n",
    "total_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造一个月的第几周\n",
    "def period_of_week(day):\n",
    "    if day in range(1, 8):\n",
    "        return 1\n",
    "    if day in range(8, 15):\n",
    "        return 2\n",
    "    if day in range(15, 22):\n",
    "        return 3\n",
    "    else:\n",
    "        return 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>dayofweek</th>\n",
       "      <th>month</th>\n",
       "      <th>dayofmonth</th>\n",
       "      <th>weekend_sat</th>\n",
       "      <th>weekend_sun</th>\n",
       "      <th>period_of_month</th>\n",
       "      <th>period_of_week</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption  dayofweek  month  dayofmonth  weekend_sat  \\\n",
       "0  2015-01-01          2900575.0          3      1           1            0   \n",
       "1  2015-01-02          3158211.0          4      1           2            0   \n",
       "2  2015-01-03          3596487.0          5      1           3            1   \n",
       "3  2015-01-04          3939672.0          6      1           4            0   \n",
       "4  2015-01-05          4101790.0          0      1           5            0   \n",
       "\n",
       "   weekend_sun  period_of_month  period_of_week  \n",
       "0            0                1               1  \n",
       "1            0                1               1  \n",
       "2            0                1               1  \n",
       "3            1                1               1  \n",
       "4            0                1               1  "
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total_df.loc[:, 'period_of_week'] = total_df['dayofmonth'].apply(lambda x:period_of_week(x))\n",
    "total_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "      <th>dayofweek</th>\n",
       "      <th>month</th>\n",
       "      <th>dayofmonth</th>\n",
       "      <th>weekend_sat</th>\n",
       "      <th>weekend_sun</th>\n",
       "      <th>period_of_month</th>\n",
       "      <th>period_of_week</th>\n",
       "      <th>festival</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2015-01-01</td>\n",
       "      <td>2900575.0</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2015-01-02</td>\n",
       "      <td>3158211.0</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2015-01-03</td>\n",
       "      <td>3596487.0</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2015-01-04</td>\n",
       "      <td>3939672.0</td>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2015-01-05</td>\n",
       "      <td>4101790.0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption  dayofweek  month  dayofmonth  weekend_sat  \\\n",
       "0  2015-01-01          2900575.0          3      1           1            0   \n",
       "1  2015-01-02          3158211.0          4      1           2            0   \n",
       "2  2015-01-03          3596487.0          5      1           3            1   \n",
       "3  2015-01-04          3939672.0          6      1           4            0   \n",
       "4  2015-01-05          4101790.0          0      1           5            0   \n",
       "\n",
       "   weekend_sun  period_of_month  period_of_week  festival  \n",
       "0            0                1               1         0  \n",
       "1            0                1               1         0  \n",
       "2            0                1               1         0  \n",
       "3            1                1               1         0  \n",
       "4            0                1               1         0  "
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 填充法定节假日 - 国庆\n",
    "total_df.loc[:, 'festival'] = 0\n",
    "total_df.loc[(total_df['month']==10) & (total_df['dayofmonth']<8), 'festival'] = 1\n",
    "total_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.分离训练集和测试集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "每天的总用电量 power_consumption 作为标签值，其余字段除了 record_date 外作为特征值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_X = total_df[total_df.record_date < '2016-10-01']\n",
    "train_y = total_df[total_df.record_date < '2016-10-01']['power_consumption']\n",
    "test_X = total_df[total_df.record_date >= '2016-10-01']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 删除训练集和测试集中的 record_date 和 power_consumption 字段\n",
    "drop_col = ['record_date', 'power_consumption']\n",
    "train_X = train_X.drop(columns=drop_col, axis=1)\n",
    "test_X = test_X.drop(columns=drop_col, axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.随机森林模型建模"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 引入随机森林模型\n",
    "from sklearn.ensemble import RandomForestRegressor\n",
    "from sklearn.model_selection import GridSearchCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on class RandomForestRegressor in module sklearn.ensemble._forest:\n",
      "\n",
      "class RandomForestRegressor(ForestRegressor)\n",
      " |  RandomForestRegressor(n_estimators=100, *, criterion='mse', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, ccp_alpha=0.0, max_samples=None)\n",
      " |  \n",
      " |  A random forest regressor.\n",
      " |  \n",
      " |  A random forest is a meta estimator that fits a number of classifying\n",
      " |  decision trees on various sub-samples of the dataset and uses averaging\n",
      " |  to improve the predictive accuracy and control over-fitting.\n",
      " |  The sub-sample size is controlled with the `max_samples` parameter if\n",
      " |  `bootstrap=True` (default), otherwise the whole dataset is used to build\n",
      " |  each tree.\n",
      " |  \n",
      " |  Read more in the :ref:`User Guide <forest>`.\n",
      " |  \n",
      " |  Parameters\n",
      " |  ----------\n",
      " |  n_estimators : int, default=100\n",
      " |      The number of trees in the forest.\n",
      " |  \n",
      " |      .. versionchanged:: 0.22\n",
      " |         The default value of ``n_estimators`` changed from 10 to 100\n",
      " |         in 0.22.\n",
      " |  \n",
      " |  criterion : {\"mse\", \"mae\"}, default=\"mse\"\n",
      " |      The function to measure the quality of a split. Supported criteria\n",
      " |      are \"mse\" for the mean squared error, which is equal to variance\n",
      " |      reduction as feature selection criterion, and \"mae\" for the mean\n",
      " |      absolute error.\n",
      " |  \n",
      " |      .. versionadded:: 0.18\n",
      " |         Mean Absolute Error (MAE) criterion.\n",
      " |  \n",
      " |  max_depth : int, default=None\n",
      " |      The maximum depth of the tree. If None, then nodes are expanded until\n",
      " |      all leaves are pure or until all leaves contain less than\n",
      " |      min_samples_split samples.\n",
      " |  \n",
      " |  min_samples_split : int or float, default=2\n",
      " |      The minimum number of samples required to split an internal node:\n",
      " |  \n",
      " |      - If int, then consider `min_samples_split` as the minimum number.\n",
      " |      - If float, then `min_samples_split` is a fraction and\n",
      " |        `ceil(min_samples_split * n_samples)` are the minimum\n",
      " |        number of samples for each split.\n",
      " |  \n",
      " |      .. versionchanged:: 0.18\n",
      " |         Added float values for fractions.\n",
      " |  \n",
      " |  min_samples_leaf : int or float, default=1\n",
      " |      The minimum number of samples required to be at a leaf node.\n",
      " |      A split point at any depth will only be considered if it leaves at\n",
      " |      least ``min_samples_leaf`` training samples in each of the left and\n",
      " |      right branches.  This may have the effect of smoothing the model,\n",
      " |      especially in regression.\n",
      " |  \n",
      " |      - If int, then consider `min_samples_leaf` as the minimum number.\n",
      " |      - If float, then `min_samples_leaf` is a fraction and\n",
      " |        `ceil(min_samples_leaf * n_samples)` are the minimum\n",
      " |        number of samples for each node.\n",
      " |  \n",
      " |      .. versionchanged:: 0.18\n",
      " |         Added float values for fractions.\n",
      " |  \n",
      " |  min_weight_fraction_leaf : float, default=0.0\n",
      " |      The minimum weighted fraction of the sum total of weights (of all\n",
      " |      the input samples) required to be at a leaf node. Samples have\n",
      " |      equal weight when sample_weight is not provided.\n",
      " |  \n",
      " |  max_features : {\"auto\", \"sqrt\", \"log2\"}, int or float, default=\"auto\"\n",
      " |      The number of features to consider when looking for the best split:\n",
      " |  \n",
      " |      - If int, then consider `max_features` features at each split.\n",
      " |      - If float, then `max_features` is a fraction and\n",
      " |        `int(max_features * n_features)` features are considered at each\n",
      " |        split.\n",
      " |      - If \"auto\", then `max_features=n_features`.\n",
      " |      - If \"sqrt\", then `max_features=sqrt(n_features)`.\n",
      " |      - If \"log2\", then `max_features=log2(n_features)`.\n",
      " |      - If None, then `max_features=n_features`.\n",
      " |  \n",
      " |      Note: the search for a split does not stop until at least one\n",
      " |      valid partition of the node samples is found, even if it requires to\n",
      " |      effectively inspect more than ``max_features`` features.\n",
      " |  \n",
      " |  max_leaf_nodes : int, default=None\n",
      " |      Grow trees with ``max_leaf_nodes`` in best-first fashion.\n",
      " |      Best nodes are defined as relative reduction in impurity.\n",
      " |      If None then unlimited number of leaf nodes.\n",
      " |  \n",
      " |  min_impurity_decrease : float, default=0.0\n",
      " |      A node will be split if this split induces a decrease of the impurity\n",
      " |      greater than or equal to this value.\n",
      " |  \n",
      " |      The weighted impurity decrease equation is the following::\n",
      " |  \n",
      " |          N_t / N * (impurity - N_t_R / N_t * right_impurity\n",
      " |                              - N_t_L / N_t * left_impurity)\n",
      " |  \n",
      " |      where ``N`` is the total number of samples, ``N_t`` is the number of\n",
      " |      samples at the current node, ``N_t_L`` is the number of samples in the\n",
      " |      left child, and ``N_t_R`` is the number of samples in the right child.\n",
      " |  \n",
      " |      ``N``, ``N_t``, ``N_t_R`` and ``N_t_L`` all refer to the weighted sum,\n",
      " |      if ``sample_weight`` is passed.\n",
      " |  \n",
      " |      .. versionadded:: 0.19\n",
      " |  \n",
      " |  min_impurity_split : float, default=None\n",
      " |      Threshold for early stopping in tree growth. A node will split\n",
      " |      if its impurity is above the threshold, otherwise it is a leaf.\n",
      " |  \n",
      " |      .. deprecated:: 0.19\n",
      " |         ``min_impurity_split`` has been deprecated in favor of\n",
      " |         ``min_impurity_decrease`` in 0.19. The default value of\n",
      " |         ``min_impurity_split`` has changed from 1e-7 to 0 in 0.23 and it\n",
      " |         will be removed in 0.25. Use ``min_impurity_decrease`` instead.\n",
      " |  \n",
      " |  bootstrap : bool, default=True\n",
      " |      Whether bootstrap samples are used when building trees. If False, the\n",
      " |      whole dataset is used to build each tree.\n",
      " |  \n",
      " |  oob_score : bool, default=False\n",
      " |      whether to use out-of-bag samples to estimate\n",
      " |      the R^2 on unseen data.\n",
      " |  \n",
      " |  n_jobs : int, default=None\n",
      " |      The number of jobs to run in parallel. :meth:`fit`, :meth:`predict`,\n",
      " |      :meth:`decision_path` and :meth:`apply` are all parallelized over the\n",
      " |      trees. ``None`` means 1 unless in a :obj:`joblib.parallel_backend`\n",
      " |      context. ``-1`` means using all processors. See :term:`Glossary\n",
      " |      <n_jobs>` for more details.\n",
      " |  \n",
      " |  random_state : int or RandomState, default=None\n",
      " |      Controls both the randomness of the bootstrapping of the samples used\n",
      " |      when building trees (if ``bootstrap=True``) and the sampling of the\n",
      " |      features to consider when looking for the best split at each node\n",
      " |      (if ``max_features < n_features``).\n",
      " |      See :term:`Glossary <random_state>` for details.\n",
      " |  \n",
      " |  verbose : int, default=0\n",
      " |      Controls the verbosity when fitting and predicting.\n",
      " |  \n",
      " |  warm_start : bool, default=False\n",
      " |      When set to ``True``, reuse the solution of the previous call to fit\n",
      " |      and add more estimators to the ensemble, otherwise, just fit a whole\n",
      " |      new forest. See :term:`the Glossary <warm_start>`.\n",
      " |  \n",
      " |  ccp_alpha : non-negative float, default=0.0\n",
      " |      Complexity parameter used for Minimal Cost-Complexity Pruning. The\n",
      " |      subtree with the largest cost complexity that is smaller than\n",
      " |      ``ccp_alpha`` will be chosen. By default, no pruning is performed. See\n",
      " |      :ref:`minimal_cost_complexity_pruning` for details.\n",
      " |  \n",
      " |      .. versionadded:: 0.22\n",
      " |  \n",
      " |  max_samples : int or float, default=None\n",
      " |      If bootstrap is True, the number of samples to draw from X\n",
      " |      to train each base estimator.\n",
      " |  \n",
      " |      - If None (default), then draw `X.shape[0]` samples.\n",
      " |      - If int, then draw `max_samples` samples.\n",
      " |      - If float, then draw `max_samples * X.shape[0]` samples. Thus,\n",
      " |        `max_samples` should be in the interval `(0, 1)`.\n",
      " |  \n",
      " |      .. versionadded:: 0.22\n",
      " |  \n",
      " |  Attributes\n",
      " |  ----------\n",
      " |  base_estimator_ : DecisionTreeRegressor\n",
      " |      The child estimator template used to create the collection of fitted\n",
      " |      sub-estimators.\n",
      " |  \n",
      " |  estimators_ : list of DecisionTreeRegressor\n",
      " |      The collection of fitted sub-estimators.\n",
      " |  \n",
      " |  feature_importances_ : ndarray of shape (n_features,)\n",
      " |      The impurity-based feature importances.\n",
      " |      The higher, the more important the feature.\n",
      " |      The importance of a feature is computed as the (normalized)\n",
      " |      total reduction of the criterion brought by that feature.  It is also\n",
      " |      known as the Gini importance.\n",
      " |  \n",
      " |      Warning: impurity-based feature importances can be misleading for\n",
      " |      high cardinality features (many unique values). See\n",
      " |      :func:`sklearn.inspection.permutation_importance` as an alternative.\n",
      " |  \n",
      " |  n_features_ : int\n",
      " |      The number of features when ``fit`` is performed.\n",
      " |  \n",
      " |  n_outputs_ : int\n",
      " |      The number of outputs when ``fit`` is performed.\n",
      " |  \n",
      " |  oob_score_ : float\n",
      " |      Score of the training dataset obtained using an out-of-bag estimate.\n",
      " |      This attribute exists only when ``oob_score`` is True.\n",
      " |  \n",
      " |  oob_prediction_ : ndarray of shape (n_samples,)\n",
      " |      Prediction computed with out-of-bag estimate on the training set.\n",
      " |      This attribute exists only when ``oob_score`` is True.\n",
      " |  \n",
      " |  See Also\n",
      " |  --------\n",
      " |  DecisionTreeRegressor, ExtraTreesRegressor\n",
      " |  \n",
      " |  Notes\n",
      " |  -----\n",
      " |  The default values for the parameters controlling the size of the trees\n",
      " |  (e.g. ``max_depth``, ``min_samples_leaf``, etc.) lead to fully grown and\n",
      " |  unpruned trees which can potentially be very large on some data sets. To\n",
      " |  reduce memory consumption, the complexity and size of the trees should be\n",
      " |  controlled by setting those parameter values.\n",
      " |  \n",
      " |  The features are always randomly permuted at each split. Therefore,\n",
      " |  the best found split may vary, even with the same training data,\n",
      " |  ``max_features=n_features`` and ``bootstrap=False``, if the improvement\n",
      " |  of the criterion is identical for several splits enumerated during the\n",
      " |  search of the best split. To obtain a deterministic behaviour during\n",
      " |  fitting, ``random_state`` has to be fixed.\n",
      " |  \n",
      " |  The default value ``max_features=\"auto\"`` uses ``n_features``\n",
      " |  rather than ``n_features / 3``. The latter was originally suggested in\n",
      " |  [1], whereas the former was more recently justified empirically in [2].\n",
      " |  \n",
      " |  References\n",
      " |  ----------\n",
      " |  .. [1] L. Breiman, \"Random Forests\", Machine Learning, 45(1), 5-32, 2001.\n",
      " |  \n",
      " |  .. [2] P. Geurts, D. Ernst., and L. Wehenkel, \"Extremely randomized\n",
      " |         trees\", Machine Learning, 63(1), 3-42, 2006.\n",
      " |  \n",
      " |  Examples\n",
      " |  --------\n",
      " |  >>> from sklearn.ensemble import RandomForestRegressor\n",
      " |  >>> from sklearn.datasets import make_regression\n",
      " |  >>> X, y = make_regression(n_features=4, n_informative=2,\n",
      " |  ...                        random_state=0, shuffle=False)\n",
      " |  >>> regr = RandomForestRegressor(max_depth=2, random_state=0)\n",
      " |  >>> regr.fit(X, y)\n",
      " |  RandomForestRegressor(...)\n",
      " |  >>> print(regr.predict([[0, 0, 0, 0]]))\n",
      " |  [-8.32987858]\n",
      " |  \n",
      " |  Method resolution order:\n",
      " |      RandomForestRegressor\n",
      " |      ForestRegressor\n",
      " |      sklearn.base.RegressorMixin\n",
      " |      BaseForest\n",
      " |      sklearn.base.MultiOutputMixin\n",
      " |      sklearn.ensemble._base.BaseEnsemble\n",
      " |      sklearn.base.MetaEstimatorMixin\n",
      " |      sklearn.base.BaseEstimator\n",
      " |      builtins.object\n",
      " |  \n",
      " |  Methods defined here:\n",
      " |  \n",
      " |  __init__(self, n_estimators=100, *, criterion='mse', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, ccp_alpha=0.0, max_samples=None)\n",
      " |      Initialize self.  See help(type(self)) for accurate signature.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data and other attributes defined here:\n",
      " |  \n",
      " |  __abstractmethods__ = frozenset()\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from ForestRegressor:\n",
      " |  \n",
      " |  predict(self, X)\n",
      " |      Predict regression target for X.\n",
      " |      \n",
      " |      The predicted regression target of an input sample is computed as the\n",
      " |      mean predicted regression targets of the trees in the forest.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      X : {array-like, sparse matrix} of shape (n_samples, n_features)\n",
      " |          The input samples. Internally, its dtype will be converted to\n",
      " |          ``dtype=np.float32``. If a sparse matrix is provided, it will be\n",
      " |          converted into a sparse ``csr_matrix``.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      y : ndarray of shape (n_samples,) or (n_samples, n_outputs)\n",
      " |          The predicted values.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from sklearn.base.RegressorMixin:\n",
      " |  \n",
      " |  score(self, X, y, sample_weight=None)\n",
      " |      Return the coefficient of determination R^2 of the prediction.\n",
      " |      \n",
      " |      The coefficient R^2 is defined as (1 - u/v), where u is the residual\n",
      " |      sum of squares ((y_true - y_pred) ** 2).sum() and v is the total\n",
      " |      sum of squares ((y_true - y_true.mean()) ** 2).sum().\n",
      " |      The best possible score is 1.0 and it can be negative (because the\n",
      " |      model can be arbitrarily worse). A constant model that always\n",
      " |      predicts the expected value of y, disregarding the input features,\n",
      " |      would get a R^2 score of 0.0.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      X : array-like of shape (n_samples, n_features)\n",
      " |          Test samples. For some estimators this may be a\n",
      " |          precomputed kernel matrix or a list of generic objects instead,\n",
      " |          shape = (n_samples, n_samples_fitted),\n",
      " |          where n_samples_fitted is the number of\n",
      " |          samples used in the fitting for the estimator.\n",
      " |      \n",
      " |      y : array-like of shape (n_samples,) or (n_samples, n_outputs)\n",
      " |          True values for X.\n",
      " |      \n",
      " |      sample_weight : array-like of shape (n_samples,), default=None\n",
      " |          Sample weights.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      score : float\n",
      " |          R^2 of self.predict(X) wrt. y.\n",
      " |      \n",
      " |      Notes\n",
      " |      -----\n",
      " |      The R2 score used when calling ``score`` on a regressor uses\n",
      " |      ``multioutput='uniform_average'`` from version 0.23 to keep consistent\n",
      " |      with default value of :func:`~sklearn.metrics.r2_score`.\n",
      " |      This influences the ``score`` method of all the multioutput\n",
      " |      regressors (except for\n",
      " |      :class:`~sklearn.multioutput.MultiOutputRegressor`).\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors inherited from sklearn.base.RegressorMixin:\n",
      " |  \n",
      " |  __dict__\n",
      " |      dictionary for instance variables (if defined)\n",
      " |  \n",
      " |  __weakref__\n",
      " |      list of weak references to the object (if defined)\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from BaseForest:\n",
      " |  \n",
      " |  apply(self, X)\n",
      " |      Apply trees in the forest to X, return leaf indices.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      X : {array-like, sparse matrix} of shape (n_samples, n_features)\n",
      " |          The input samples. Internally, its dtype will be converted to\n",
      " |          ``dtype=np.float32``. If a sparse matrix is provided, it will be\n",
      " |          converted into a sparse ``csr_matrix``.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      X_leaves : ndarray of shape (n_samples, n_estimators)\n",
      " |          For each datapoint x in X and for each tree in the forest,\n",
      " |          return the index of the leaf x ends up in.\n",
      " |  \n",
      " |  decision_path(self, X)\n",
      " |      Return the decision path in the forest.\n",
      " |      \n",
      " |      .. versionadded:: 0.18\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      X : {array-like, sparse matrix} of shape (n_samples, n_features)\n",
      " |          The input samples. Internally, its dtype will be converted to\n",
      " |          ``dtype=np.float32``. If a sparse matrix is provided, it will be\n",
      " |          converted into a sparse ``csr_matrix``.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      indicator : sparse matrix of shape (n_samples, n_nodes)\n",
      " |          Return a node indicator matrix where non zero elements indicates\n",
      " |          that the samples goes through the nodes. The matrix is of CSR\n",
      " |          format.\n",
      " |      \n",
      " |      n_nodes_ptr : ndarray of shape (n_estimators + 1,)\n",
      " |          The columns from indicator[n_nodes_ptr[i]:n_nodes_ptr[i+1]]\n",
      " |          gives the indicator value for the i-th estimator.\n",
      " |  \n",
      " |  fit(self, X, y, sample_weight=None)\n",
      " |      Build a forest of trees from the training set (X, y).\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      X : {array-like, sparse matrix} of shape (n_samples, n_features)\n",
      " |          The training input samples. Internally, its dtype will be converted\n",
      " |          to ``dtype=np.float32``. If a sparse matrix is provided, it will be\n",
      " |          converted into a sparse ``csc_matrix``.\n",
      " |      \n",
      " |      y : array-like of shape (n_samples,) or (n_samples, n_outputs)\n",
      " |          The target values (class labels in classification, real numbers in\n",
      " |          regression).\n",
      " |      \n",
      " |      sample_weight : array-like of shape (n_samples,), default=None\n",
      " |          Sample weights. If None, then samples are equally weighted. Splits\n",
      " |          that would create child nodes with net zero or negative weight are\n",
      " |          ignored while searching for a split in each node. In the case of\n",
      " |          classification, splits are also ignored if they would result in any\n",
      " |          single class carrying a negative weight in either child node.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      self : object\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Readonly properties inherited from BaseForest:\n",
      " |  \n",
      " |  feature_importances_\n",
      " |      The impurity-based feature importances.\n",
      " |      \n",
      " |      The higher, the more important the feature.\n",
      " |      The importance of a feature is computed as the (normalized)\n",
      " |      total reduction of the criterion brought by that feature.  It is also\n",
      " |      known as the Gini importance.\n",
      " |      \n",
      " |      Warning: impurity-based feature importances can be misleading for\n",
      " |      high cardinality features (many unique values). See\n",
      " |      :func:`sklearn.inspection.permutation_importance` as an alternative.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      feature_importances_ : ndarray of shape (n_features,)\n",
      " |          The values of this array sum to 1, unless all trees are single node\n",
      " |          trees consisting of only the root node, in which case it will be an\n",
      " |          array of zeros.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from sklearn.ensemble._base.BaseEnsemble:\n",
      " |  \n",
      " |  __getitem__(self, index)\n",
      " |      Return the index'th estimator in the ensemble.\n",
      " |  \n",
      " |  __iter__(self)\n",
      " |      Return iterator over estimators in the ensemble.\n",
      " |  \n",
      " |  __len__(self)\n",
      " |      Return the number of estimators in the ensemble.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data and other attributes inherited from sklearn.ensemble._base.BaseEnsemble:\n",
      " |  \n",
      " |  __annotations__ = {'_required_parameters': typing.List[str]}\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from sklearn.base.BaseEstimator:\n",
      " |  \n",
      " |  __getstate__(self)\n",
      " |  \n",
      " |  __repr__(self, N_CHAR_MAX=700)\n",
      " |      Return repr(self).\n",
      " |  \n",
      " |  __setstate__(self, state)\n",
      " |  \n",
      " |  get_params(self, deep=True)\n",
      " |      Get parameters for this estimator.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      deep : bool, default=True\n",
      " |          If True, will return the parameters for this estimator and\n",
      " |          contained subobjects that are estimators.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      params : mapping of string to any\n",
      " |          Parameter names mapped to their values.\n",
      " |  \n",
      " |  set_params(self, **params)\n",
      " |      Set the parameters of this estimator.\n",
      " |      \n",
      " |      The method works on simple estimators as well as on nested objects\n",
      " |      (such as pipelines). The latter have parameters of the form\n",
      " |      ``<component>__<parameter>`` so that it's possible to update each\n",
      " |      component of a nested object.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      **params : dict\n",
      " |          Estimator parameters.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      self : object\n",
      " |          Estimator instance.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(RandomForestRegressor)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "param_grid = {'n_estimators': [5, 10, 20, 40, 80, 160],\n",
    "             'max_depth': [3, 5, 7, 9, 11],\n",
    "             'max_features': [0.6, 0.7, 0.8]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "rf = RandomForestRegressor()\n",
    "# 使用网格搜索进行参数调优\n",
    "grid = GridSearchCV(rf, param_grid=param_grid, cv=3, n_jobs=6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. 模型拟合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GridSearchCV(cv=3, error_score='raise-deprecating',\n",
       "             estimator=RandomForestRegressor(bootstrap=True, criterion='mse',\n",
       "                                             max_depth=None,\n",
       "                                             max_features='auto',\n",
       "                                             max_leaf_nodes=None,\n",
       "                                             min_impurity_decrease=0.0,\n",
       "                                             min_impurity_split=None,\n",
       "                                             min_samples_leaf=1,\n",
       "                                             min_samples_split=2,\n",
       "                                             min_weight_fraction_leaf=0.0,\n",
       "                                             n_estimators='warn', n_jobs=None,\n",
       "                                             oob_score=False, random_state=None,\n",
       "                                             verbose=0, warm_start=False),\n",
       "             iid='warn', n_jobs=6,\n",
       "             param_grid={'max_depth': [3, 5, 7, 9, 11],\n",
       "                         'max_features': [0.6, 0.7, 0.8],\n",
       "                         'n_estimators': [5, 10, 20, 40, 80, 160]},\n",
       "             pre_dispatch='2*n_jobs', refit=True, return_train_score=False,\n",
       "             scoring=None, verbose=0)"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid.fit(train_X, train_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.44107416505038555"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grid.score(train_X, train_y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8.模型预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3567043.58471521, 3380735.03115951, 3547992.61065724,\n",
       "       3547992.61065724, 3547992.61065724, 3547992.61065724,\n",
       "       3547992.61065724, 3831517.50636324, 3659420.39006999,\n",
       "       3877982.44714284, 3877982.44714284, 3877982.44714284,\n",
       "       3895358.33857682, 3895358.33857682, 3829610.86526292,\n",
       "       3697755.11966299, 3895358.33857682, 3895358.33857682,\n",
       "       3895358.33857682, 3895358.33857682, 3914847.73639577,\n",
       "       3849100.26308187, 3717244.51748194, 3914847.73639577,\n",
       "       3914847.73639577, 3914847.73639577, 3914847.73639577,\n",
       "       3914847.73639577, 3849100.26308187, 3717244.51748194,\n",
       "       3914847.73639577])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predictions = grid.predict(test_X)\n",
    "predictions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.生成CSV文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2016-10-01</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2016-10-02</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2016-10-03</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2016-10-04</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2016-10-05</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption\n",
       "0  2016-10-01                  0\n",
       "1  2016-10-02                  0\n",
       "2  2016-10-03                  0\n",
       "3  2016-10-04                  0\n",
       "4  2016-10-05                  0"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>record_date</th>\n",
       "      <th>power_consumption</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>2016-10-01</td>\n",
       "      <td>3.567044e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2016-10-02</td>\n",
       "      <td>3.380735e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2016-10-03</td>\n",
       "      <td>3.547993e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2016-10-04</td>\n",
       "      <td>3.547993e+06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2016-10-05</td>\n",
       "      <td>3.547993e+06</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  record_date  power_consumption\n",
       "0  2016-10-01       3.567044e+06\n",
       "1  2016-10-02       3.380735e+06\n",
       "2  2016-10-03       3.547993e+06\n",
       "3  2016-10-04       3.547993e+06\n",
       "4  2016-10-05       3.547993e+06"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_df.loc[:, 'power_consumption'] = predictions\n",
    "test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_df.to_csv('./tree_prediction.csv', index=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
